
package br.ufu.lsi.database.collector.old;

import java.io.BufferedWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import twitter4j.IDs;
import twitter4j.JSONArray;
import twitter4j.JSONObject;
import twitter4j.RateLimitStatus;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.User;
import br.ufu.lsi.database.factory.TwitterBuilder;
import br.ufu.lsi.database.model.Follow;
import br.ufu.lsi.util.FileUtil;
import br.ufu.lsi.util.PropertiesUtil;

import com.google.gson.Gson;

public class FollowersListThread implements Runnable {

    private static final String FOLLOWERS_DIR = PropertiesUtil.getProperty( "FOLLOWERS_DIR" );

    long userId;

    Twitter twitter;

    BufferedWriter writer;

    public FollowersListThread( Twitter twitter, long userId ) {
        this.userId = userId;
        this.twitter = twitter;
    }

    public void run() {

        try {

            // get all followers of main user
            JSONObject jo = new JSONObject();
            followersList( twitter, userId, jo );
            JSONArray followersRaw = ( JSONArray ) jo.get( "followers" );

            ArrayList< Follow > followersOfMainUser = new ArrayList< Follow >();
            JSONArray jsonArray = ( JSONArray ) followersRaw;
            if ( jsonArray != null ) {
                int len = jsonArray.length();
                for ( int i = 0; i < len; i++ ) {
                    Follow follow = new Gson()
                            .fromJson( jsonArray.get( i ).toString(), Follow.class );
                    followersOfMainUser.add( follow );
                }
            }
            System.out.println( "Followers captured from main user = " + followersOfMainUser.size() );

            // for each follower, get followers and friends (get social network)
            BufferedWriter bw = FileUtil.openOutputFile( FOLLOWERS_DIR + userId );

            for ( Follow follow : followersOfMainUser ) {
                writeNodeInfo( twitter, follow.getFollower().getId(), bw );
            }

            bw.close();

        } catch ( Exception e ) {
            e.printStackTrace();
        }
    }

    public static void writeNodeInfo( Twitter twitter, long userId, BufferedWriter bw ) throws Exception {

        JSONObject jo = new JSONObject();
        personalInfo( twitter, userId, jo );
        followersList( twitter, userId, jo );
        friendsList( twitter, userId, jo );
        bw.write( jo.toString() + "\n" );
    }

    public static void personalInfo( Twitter twitter, long userId, JSONObject jo ) throws Exception {

        User user = twitter.showUser( userId );
        jo.put( "id", user.getId() );
        jo.put( "screenName", user.getScreenName() );
        
        System.out.println( "getting info from [" + user.getId() + ", " + user.getScreenName() + "]");
    }

    public static void followersList( Twitter twitter, long userId, JSONObject jo ) throws Exception {

        IDs followers;
        long cursor = - 1;
        Set< Follow > followersRelations = new HashSet< Follow >();
        do {
            followers = getFollowersIDs( twitter, userId, cursor );
            
            if( followers == null ) {
                break;
            }

            System.out.println( "got " + followers.getIDs().length + " followers..." );

            for ( long id : followers.getIDs() ) {
                br.ufu.lsi.database.model.User followee = new br.ufu.lsi.database.model.User();
                br.ufu.lsi.database.model.User follower = new br.ufu.lsi.database.model.User();

                followee.setId( userId );
                follower.setId( id );

                Follow follow = new Follow();
                follow.setFollowee( followee );
                follow.setFollower( follower );
                follow.setInit( System.currentTimeMillis() );

                followersRelations.add( follow );
            }
        } while ( ( cursor = followers.getNextCursor() ) != 0 );
        jo.put( "followers", followersRelations );

    }

    public static void friendsList( Twitter twitter, long userId, JSONObject jo ) throws Exception {

        IDs friends;
        long cursor = -1;
        Set< Follow > friendsRelations = new HashSet< Follow >();
        do {
            friends = getFriendsIDs( twitter, userId, cursor );

            if( friends == null ) {
                break;
            }
            
            System.out.println( "got " + friends.getIDs().length + " friends..." );

            for ( long id : friends.getIDs() ) {
                br.ufu.lsi.database.model.User followee = new br.ufu.lsi.database.model.User();
                br.ufu.lsi.database.model.User follower = new br.ufu.lsi.database.model.User();

                followee.setId( id );
                follower.setId( userId );

                Follow follow = new Follow();
                follow.setFollowee( followee );
                follow.setFollower( follower );

                follow.setInit( System.currentTimeMillis() );

                friendsRelations.add( follow );
            }

        } while ( ( cursor = friends.getNextCursor() ) != 0 );
        jo.put( "friends", friendsRelations );
    }

    public static IDs getFriendsIDs( Twitter twitter, long userId, long cursor ) throws Exception {

        try {

            return twitter.getFriendsIDs( userId, cursor );

        } catch ( TwitterException e ) {
            messageTwitterException( e );
            if ( e.getStatusCode() == 429 ) {
                handleTwitterException( e, twitter, "/friends/ids" );
            }
        } catch ( Exception e ) {
            e.printStackTrace();
        }

        return null;
    }

    public static IDs getFollowersIDs( Twitter twitter, long userId, long cursor ) throws Exception {

        try {
            return twitter.getFollowersIDs( userId, cursor );
        } catch ( TwitterException e ) {

            messageTwitterException( e );
            if ( e.getStatusCode() == 429 ) {

                handleTwitterException( e, twitter, "/followers/ids" );

                return getFollowersIDs( twitter, userId, cursor );
            }
        } catch ( Exception e ) {
            e.printStackTrace();
        }
        return null;
    }

    public static void messageTwitterException( TwitterException e ) {

        System.out.println( "\n-------------------------------> " + e.getErrorMessage() + " ("
                + e.getStatusCode() + ") " );
        e.printStackTrace();
    }

    public static void handleTwitterException( TwitterException e, Twitter twitter, String keyStatus ) {
        
        RateLimitStatus status = e.getRateLimitStatus();
        try {
            System.out.print( "[" + new Date( System.currentTimeMillis() ) + "] " );
            System.out.println( "Sleeping thread " + Thread.currentThread().getName() + " during "
                    + status.getSecondsUntilReset() + "sec ( "
                    + twitter.getOAuthAccessToken().getToken() + " ) ..." );

            if ( status.getSecondsUntilReset() > 0 )
                Thread.sleep( status.getSecondsUntilReset() * 1000 + 60000 );
            
            
        } catch ( TwitterException e1 ) {
            e1.printStackTrace();
        } catch ( InterruptedException e2 ) {
            e2.printStackTrace();
        }
    }
}
